package com.asset.config.shiro;

import com.asset.config.shiro.jwt.JwtToken;
import com.asset.modules.common.utils.Constant;
import com.asset.modules.common.utils.JedisUtil;
import com.asset.modules.common.utils.JwtUtil;
import com.asset.modules.common.utils.StringUtil;
import com.asset.modules.system.model.User;
import com.asset.modules.system.service.RoleService;
import com.asset.modules.system.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义Realm
 * @author dolyw.com
 * @date 2018/8/30 14:10
 */
@Service
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService sysUserService;
    @Autowired
    private RoleService sysRoleService;


    /**
     * 大坑，必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken authenticationToken) {
        return authenticationToken instanceof JwtToken;
    }

    /**
     * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        String account = JwtUtil.getClaim(principalCollection.toString(), Constant.ACCOUNT);
        User user = sysUserService.getUser("user_name", account);
        // 查询用户角色
        simpleAuthorizationInfo.addRole(user.getRoleName());
        List<String> permissions = new ArrayList<>();
        permissions.add(user.getCompanyCode());
        permissions.add(user.getPermission());
        simpleAuthorizationInfo.addStringPermissions(permissions);
//        List<Role> roleList = sysUserService.querySysRolesByUsername(account);
//        for (SysRole sysRole : roleList) {
//            if (sysRole != null) {
//                // 添加角色
//                simpleAuthorizationInfo.addRole(sysRole.getRole());
//                // 根据用户角色查询权限
//                List<SysPermission> sysPermissionList = sysRoleService.querySysPermissionsByRole(sysRole.getRole());
//                for (SysPermission sysPermission : sysPermissionList) {
//                    if (sysPermission != null) {
//                        // 添加权限
//                        simpleAuthorizationInfo.addStringPermission(sysPermission.getName());
//                    }
//                }
//            }
//        }
        return simpleAuthorizationInfo;
    }

    /**
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可。
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        // 解密获得account，用于和数据库进行对比
        String username = JwtUtil.getClaim(token, Constant.ACCOUNT);
        // 帐号为空
        if (StringUtil.isBlank(username)) {
            throw new AuthenticationException("Token中帐号为空(The account in Token is empty.)");
        }
        // 查询用户是否存在
        User user = sysUserService.getUser("user_name", username);
        if (user == null) {
            throw new AuthenticationException("该帐号不存在(The account does not exist.)");
        }
//        //查询账户可用状态
//        if(user.get()==0){
//            throw new AuthenticationException("该帐号已被锁定(The account is locked.)");
//        }
        // 开始认证，要AccessToken认证通过，且Redis中存在RefreshToken，且两个Token时间戳一致
        if (JwtUtil.verify(token) && JedisUtil.exists(Constant.PREFIX_SHIRO_REFRESH_TOKEN + username)) {
            // 获取RefreshToken的时间戳
            String currentTimeMillisRedis = JedisUtil.getObject(Constant.PREFIX_SHIRO_REFRESH_TOKEN + username).toString();
            // 获取AccessToken时间戳，与RefreshToken的时间戳对比
            if (JwtUtil.getClaim(token, Constant.CURRENT_TIME_MILLIS).equals(currentTimeMillisRedis)) {
                return new SimpleAuthenticationInfo(token, token, "userRealm");
            }
        }
        throw new AuthenticationException("Token已过期(Token expired or incorrect.)");
    }
}
